package com.example.dakotanews.service.implement;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.example.dakotanews.dto.*;
import com.example.dakotanews.dto.utils.ApiResponse;
import com.example.dakotanews.dto.utils.ResponseCode;
import com.example.dakotanews.entity.*;
import com.example.dakotanews.entity.relation.*;
import com.example.dakotanews.entity.userInfo.JWTUserInfo;
import com.example.dakotanews.mapper.*;
import com.example.dakotanews.mapper.relation.*;
import com.example.dakotanews.service.UserService;
import com.example.dakotanews.utils.JwtUtil;
import com.example.dakotanews.utils.TimeHandler;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.util.*;


@Service
public class UserServiceImpl implements UserService {

    private final JwtUtil jwtUtil;
    private final NewsMapper newsMapper;
    private final UserMapper userMapper;
    private final UserFollowingMapper userFollowingMapper;
    private final IssueFollowingMapper issueFollowingMapper;
    private final SectionFollowingMapper sectionFollowingMapper;
    private final IssueMapper issueMapper;
    private final BlogSectionMapper blogSectionMapper;
    private final BlogMapper blogMapper;
    private final BlogMarkMapper blogMarkMapper;
    private final NewsMarkMapper newsMarkMapper;
    private final TimeHandler timeHandler;

    // 使用构造函数进行自动装配
    @Autowired
    public UserServiceImpl(
            JwtUtil jwtUtil,
            NewsMapper newsMapper,
            UserMapper userMapper,
            UserFollowingMapper userFollowingMapper,
            IssueFollowingMapper issueFollowingMapper,
            SectionFollowingMapper sectionFollowingMapper,
            IssueMapper issueMapper,
            BlogSectionMapper blogSectionMapper,
            BlogMapper blogMapper,
            BlogMarkMapper blogMarkMapper,
            NewsMarkMapper newsMarkMapper,
            TimeHandler timeHandler
    ) {
        this.jwtUtil = jwtUtil;
        this.newsMapper = newsMapper;
        this.userMapper = userMapper;
        this.userFollowingMapper = userFollowingMapper;
        this.issueFollowingMapper = issueFollowingMapper;
        this.sectionFollowingMapper = sectionFollowingMapper;
        this.issueMapper = issueMapper;
        this.blogSectionMapper = blogSectionMapper;
        this.blogMapper = blogMapper;
        this.blogMarkMapper = blogMarkMapper;
        this.newsMarkMapper = newsMarkMapper;
        this.timeHandler = timeHandler;
    }

    ApiResponse<Object> apiResponse;

    @Override
    public ApiResponse<Object> loginAuthentication(String username, String password) {
        Map<String, Object> plainUserInfo = new HashMap<>();

        User user = userMapper.selectByUsername(username);
        if (user != null) {
            if (user.getPassword().equals(password)) {
                JWTUserInfo userDetails = new JWTUserInfo(user.getNickname(), user.getUserType());
                String userJWT = jwtUtil.generateToken(user.getId(), userDetails);

                plainUserInfo.put("id", user.getId());
                plainUserInfo.put("nickname", user.getNickname());
                plainUserInfo.put("profile", user.getProfile());
                plainUserInfo.put("userType", user.getUserType());
                plainUserInfo.put("token", userJWT);

                apiResponse = new ApiResponse<>(ResponseCode.SUCCESS, "登录成功", plainUserInfo);
            } else {
                apiResponse = new ApiResponse<>(ResponseCode.UNAUTHORIZED, "密码错误", null);
            }
        } else {
            apiResponse = new ApiResponse<>(ResponseCode.NOT_FOUND, "用户不存在", null);
        }

        return apiResponse;
    }

    /**
     * @return 返回一个表示处理结果的文本
     * 返回结果：1、关注成功；2、取消关注；3、不能关注自己
     */
    @Override
    public ApiResponse<Object> userFollow(Integer followedUserId, Integer userId) {
        if (Objects.equals(followedUserId, userId)) {
            // 如果关注对象是自己
            apiResponse = new ApiResponse<>(ResponseCode.BAD_REQUEST, "请求无效", "不能关注自己");
        } else {
            // 查询关注关系是否存在
            UserFollowing userFollowing = userFollowingMapper.selectOne(new QueryWrapper<UserFollowing>()
                    .eq("followed_user_id", followedUserId)
                    .eq("user_id", userId));
            if (userFollowing != null) {
                // 若关系存在，则执行取消关注的逻辑
                userFollowingMapper.deleteById(userFollowing.getId());

                apiResponse = new ApiResponse<>(ResponseCode.SUCCESS, "请求成功", "取消关注");
            } else {
                UserFollowing userFollowing1 = new UserFollowing();
                userFollowing1.setUserId(userId);
                userFollowing1.setFollowedUserId(followedUserId);

                userFollowingMapper.insert(userFollowing1);

                apiResponse = new ApiResponse<>(ResponseCode.SUCCESS, "请求成功", "关注成功");
            }
        }
        return apiResponse;
    }

    @Override
    public ApiResponse<Object> getUserBasicInfo(Integer visitedUserId, Integer userId) {
        User visitedUser = userMapper.selectById(visitedUserId);
        Map<String, Object> data = new HashMap<>();

        if (visitedUser == null) {
            // 若查找的用户不存在
            return new ApiResponse<>(ResponseCode.NOT_FOUND, "未找到指定用户", data);
        }
        PersonalInfoDTO personalInfoDTO = new PersonalInfoDTO(visitedUser);

        if (userId != null) {
            // 若用户已登录，并且被访问用户（被关注）与登录用户（关注）的关系存在
            UserFollowing userFollowing = userFollowingMapper.selectOne(new QueryWrapper<UserFollowing>()
                    .eq("followed_user_id", visitedUserId)
                    .eq("user_id", userId));
            personalInfoDTO.setFollowedIf(userFollowing != null);
        } else {
            personalInfoDTO.setFollowedIf(false);
        }

        // 统计新闻数和博客数相加后填充
        int newsNum = Math.toIntExact(newsMapper.selectCount(new QueryWrapper<News>()
                .eq("user_id", visitedUserId)));
        int blogNum = Math.toIntExact(blogMapper.selectCount(new QueryWrapper<Blog>()
                .eq("user_id", visitedUserId)));
        personalInfoDTO.putArticles(newsNum + blogNum);

        // 获取被访用户的新闻和博客流
        List<News> newsStream = newsMapper.selectList(new QueryWrapper<News>()
                .eq("user_id", visitedUserId));
        List<Blog> blogStream = blogMapper.selectList(new QueryWrapper<Blog>()
                .eq("user_id", visitedUserId));

        // 统计新闻被点赞数和博客被点赞数相加后填充
        int newsSupportedNum = newsStream.stream().mapToInt(News::getSupportNum).sum();
        int blogSupportedNum = blogStream.stream().mapToInt(Blog::getSupportNum).sum();
        personalInfoDTO.putBeLikes(newsSupportedNum + blogSupportedNum);

        // 统计新闻被收藏数和博客被收藏数相加后填充
        int newsCollectedNum = newsStream.stream().mapToInt(News::getCollectionNum).sum();
        int blogCollectedNum = blogStream.stream().mapToInt(Blog::getCollectionNum).sum();
        personalInfoDTO.putBeCollections(newsCollectedNum + blogCollectedNum);

        // 统计收藏的新闻数
        int newsCollections = Math.toIntExact(newsMarkMapper.selectCount(new QueryWrapper<NewsMark>()
                .eq("user_id", visitedUserId)
                .eq("collection_if", 1)));
        personalInfoDTO.putNewsCollections(newsCollections);

        data.put("personalInfo", personalInfoDTO);

        return new ApiResponse<>(ResponseCode.SUCCESS, "请求成功", data);
    }

    // 目标用户为自己时，获取用户属性信息
    @Override
    public ApiResponse<Object> getSelfPropertyInfo(Integer visitedUserId) {
        Map<String, Object> data = new HashMap<>();

        List<UserNewsDTO> myNewsDTOList;
        List<UserBlogDTO> myBlogDTOList;
        List<FollowUserDTO> followUserDTOList = new ArrayList<>();
        List<FollowIssueDTO> followIssueDTOList = new ArrayList<>();
        List<FollowSectionDTO> followSectionDTOList = new ArrayList<>();

        // 获取目标用户新闻信息
        myNewsDTOList = getUserNewsByUserId(visitedUserId);

        // 获取目标用户博客信息（与新闻相同）
        myBlogDTOList = getUserBlogByUserId(visitedUserId);

        // 获取目标用户最近点赞过的新闻
        // 根据新闻标记表，获取点赞新闻的ID列表（并按点赞时间降序排序）
        List<Integer> likeNewsIds = newsMarkMapper.selectList(new QueryWrapper<NewsMark>()
                        .eq("user_id", visitedUserId)
                        .eq("support_if", 1)
                        .orderByDesc("support_time"))
                .stream()
                .map(NewsMark::getNewsId)
                .toList();
        List<UserNewsDTO> recentLikeNewsDTOList = getUserNewsByIdList(likeNewsIds);

        // 获取目标用户最近点赞过的博客
        List<Integer> likeBlogIds = blogMarkMapper.selectList(new QueryWrapper<BlogMark>()
                        .eq("user_id", visitedUserId)
                        .eq("support_if", 1)
                        .orderByDesc("support_time"))
                .stream()
                .map(BlogMark::getBlogId)
                .toList();
        List<UserBlogDTO> recentLikeBlogDTOList = getUserBlogByIdList(likeBlogIds);

        // 获取目标用户最近收藏的新闻
        List<Integer> favoriteNewsIds = newsMarkMapper.selectList(new QueryWrapper<NewsMark>()
                        .eq("user_id", visitedUserId)
                        .eq("collection_if", 1)
                        .orderByDesc("collection_time"))
                .stream()
                .map(NewsMark::getNewsId)
                .toList();
        List<UserNewsDTO> recentFavoriteNewsDTOList = getUserNewsByIdList(favoriteNewsIds);

        // 获取目标用户最近收藏的博客
        List<Integer> favoriteBlogIds = blogMarkMapper.selectList(new QueryWrapper<BlogMark>()
                        .eq("user_id", visitedUserId)
                        .eq("collection_if", 1)
                        .orderByDesc("collection_time"))
                .stream()
                .map(BlogMark::getBlogId)
                .toList();
        List<UserBlogDTO> recentFavoriteBlogDTOList = getUserBlogByIdList(favoriteBlogIds);

        // 获取目标用户关注的用户列表
        List<Integer> userIdList = userFollowingMapper.selectList(new QueryWrapper<UserFollowing>()
                        .eq("user_id", visitedUserId))
                .stream()
                .map(UserFollowing::getFollowedUserId)
                .toList();
        if (userIdList.size() != 0) {
            List<User> followUserList = userMapper.selectList(new QueryWrapper<User>()
                    .in("id", userIdList));
            for (User user : followUserList) {
                followUserDTOList.add(new FollowUserDTO(user));
            }
        }

        // 获取目标用户关注的话题列表
        List<Integer> issueIdList = issueFollowingMapper.selectList(new QueryWrapper<IssueFollowing>()
                        .eq("user_id", visitedUserId))
                .stream()
                .map(IssueFollowing::getFollowedIssueId)
                        .toList();
        if(issueIdList.size() != 0) {
            List<Issue> followIssueList = issueMapper.selectList(new QueryWrapper<Issue>()
                    .in("id", issueIdList));
            for(Issue issue: followIssueList) {
                followIssueDTOList.add(new FollowIssueDTO(issue));
            }
        }

        // 获取目标用户关注的论坛板块列表
        List<Integer> sectionIdList = sectionFollowingMapper.selectList(new QueryWrapper<SectionFollowing>()
                        .eq("user_id", visitedUserId))
                .stream()
                .map(SectionFollowing::getFollowedSectionId)
                .toList();
        if(sectionIdList.size() != 0) {
            List<BlogSection> followSectionList = blogSectionMapper.selectList(new QueryWrapper<BlogSection>()
                    .in("id", sectionIdList));
            for(BlogSection blogSection: followSectionList) {
                followSectionDTOList.add(new FollowSectionDTO(blogSection));
            }
        }


        data.put("myNewss", myNewsDTOList);
        data.put("myBlogs", myBlogDTOList);
        data.put("recentLikeNewss", recentLikeNewsDTOList);
        data.put("recentLikeBlogs", recentLikeBlogDTOList);
        data.put("recentFavoNewss", recentFavoriteNewsDTOList);
        data.put("recentFavoBlogs", recentFavoriteBlogDTOList);
        data.put("followUsers", followUserDTOList);
        data.put("followIssues", followIssueDTOList);
        data.put("followSections", followSectionDTOList);

        return new ApiResponse<>(ResponseCode.SUCCESS, "请求成功", data);
    }

    @Override
    public ApiResponse<Object> getOtherPropertyInfo(Integer visitedUserId) {
        Map<String, Object> data = new HashMap<>();

        // 获取目标用户新闻信息
        List<UserNewsDTO> myNewsDTOList = getUserNewsByUserId(visitedUserId);

        // 获取目标用户博客信息（与新闻相同）
        List<UserBlogDTO> myBlogDTOList = getUserBlogByUserId(visitedUserId);

        data.put("myNewss", myNewsDTOList);
        data.put("myBlogs", myBlogDTOList);

        return new ApiResponse<>(ResponseCode.SUCCESS, "请求成功", data);
    }

    // 根据用户ID获取新闻信息DTO列表
    protected List<UserNewsDTO> getUserNewsByUserId(Integer userId) {
        List<UserNewsDTO> myNewsDTOList = new ArrayList<>();

        List<News> myNewsList = newsMapper.selectList(new QueryWrapper<News>().eq("user_id", userId));
        if (!myNewsList.isEmpty()) {
            // 若存在以目标用户为作者的新闻
            for (News news : myNewsList) {
                // 将新闻类封装为新闻DTO类，然后装入集合
                UserNewsDTO userNewsDTO = new UserNewsDTO(news);
                LocalDateTime createdTime = news.getEditTime() == null ? news.getPublishTime() : news.getEditTime();
                userNewsDTO.setCreatedTime(timeHandler.dateTimeFormatToDay(createdTime));

                myNewsDTOList.add(userNewsDTO);
            }
        }
        return myNewsDTOList;
    }

    // 根据用户ID获取博客信息DTO列表
    protected List<UserBlogDTO> getUserBlogByUserId(Integer userId) {
        List<UserBlogDTO> myBlogDTOList = new ArrayList<>();

        List<Blog> myBlogList = blogMapper.selectList(new QueryWrapper<Blog>().eq("user_id", userId));
        if (!myBlogList.isEmpty()) {
            // 若存在以目标用户为作者的新闻
            for (Blog blog : myBlogList) {
                // 将新闻类封装为新闻DTO类，然后装入集合
                UserBlogDTO userBlogDTO = new UserBlogDTO(blog);
                LocalDateTime createdTime = blog.getEditTime() == null ? blog.getCommitTime() : blog.getEditTime();
                userBlogDTO.setCreatedTime(timeHandler.dateTimeFormatToDay(createdTime));

                myBlogDTOList.add(userBlogDTO);
            }
        }
        return myBlogDTOList;
    }

    // 根据新闻ID列表获取新闻信息DTO列表
    protected List<UserNewsDTO> getUserNewsByIdList(List<Integer> newsIds) {
        List<UserNewsDTO> newsDTOList = new ArrayList<>();

        if (newsIds.size() != 0) {
            // 若目标用户有过点赞新闻的记录
            List<News> newsList = newsMapper.selectList(new QueryWrapper<News>()
                    .in("id", newsIds));
            // 将每一条新闻记录封装为新闻DTO
            for (News news : newsList) {
                UserNewsDTO userNewsDTO = new UserNewsDTO(news);
                LocalDateTime createdTime = news.getEditTime() == null ? news.getPublishTime() : news.getEditTime();
                userNewsDTO.setCreatedTime(timeHandler.dateTimeFormatToDay(createdTime));

                newsDTOList.add(userNewsDTO);
            }
            return newsDTOList;
        } else {
            // 若没有点赞记录，则返回空集合
            return new ArrayList<>();
        }
    }

    // 根据新闻ID列表获取新闻信息DTO列表
    protected List<UserBlogDTO> getUserBlogByIdList(List<Integer> blogIds) {
        List<UserBlogDTO> blogDTOList = new ArrayList<>();

        if (blogIds.size() != 0) {
            // 若目标用户有过点赞新闻的记录
            List<Blog> blogList = blogMapper.selectList(new QueryWrapper<Blog>()
                    .in("id", blogIds));
            // 将每一条新闻记录封装为新闻DTO
            for (Blog blog : blogList) {
                UserBlogDTO userBlogDTO = new UserBlogDTO(blog);
                LocalDateTime createdTime = blog.getEditTime() == null ? blog.getCommitTime() : blog.getEditTime();
                userBlogDTO.setCreatedTime(timeHandler.dateTimeFormatToDay(createdTime));

                blogDTOList.add(userBlogDTO);
            }
            return blogDTOList;
        } else {
            // 若没有点赞记录，则返回空集合
            return new ArrayList<>();
        }
    }
}
